package com.eastfair.projectcore;


import cn.hutool.extra.spring.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.eastfair.aopcache.clone.ICloner;
import com.eastfair.aopcache.config.MethodAnnotationPointcutAdvisor;
import com.eastfair.aopcache.handler.CacheHandler;
import com.eastfair.aopcache.interceptor.AutoloadCacheProperties;
import com.eastfair.aopcache.interceptor.CacheMethodInterceptor;
import com.eastfair.aopcache.manager.*;
import com.eastfair.aopcache.model.AutoLoadConfig;
import com.eastfair.aopcache.parser.AbstractScriptParser;
import com.eastfair.aopcache.parser.SpringELParser;
import com.eastfair.aopcache.serializer.StringSerializer;
import com.eastfair.cache.repository.CacheOps;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.context.StaticContextUtil;
import com.eastfair.core.model.DataIsolationModel;
import com.eastfair.core.model.DataScopeEnum;
import com.eastfair.core.model.SystemTagEnum;
import com.eastfair.log.LampMdcAdapterInitializer;
import com.eastfair.model.DataIsolationVo;
import com.eastfair.model.TenantRuleVO;
import com.eastfair.projectcore.controller.DataIsolationController;
import com.eastfair.projectcore.controller.DictionaryController;
import com.eastfair.projectcore.controller.TenantRuleController;
import com.eastfair.projectcore.controller.WorkerNodeController;
import com.eastfair.projectcore.dto.DataIsolationDTO;
import com.eastfair.projectcore.entity.WorkerNode;
import com.eastfair.projectcore.service.WorkerNodeService;
import com.eastfair.security.annotation.EnableLoginArgResolver;
import com.eastfair.uid.baidu.impl.CachedUidGenerator;
import com.eastfair.uid.baidu.model.WorkerNodeOfUid;
import com.eastfair.uid.baidu.rule.SnowFlakeRole;
import com.eastfair.uid.baidu.utils.DockerUtils;
import com.eastfair.uid.baidu.worker.WorkerNodeType;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.env.Environment;
import org.springframework.util.CollectionUtils;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;

import static com.eastfair.constant.BizConstant.UTIL_PACKAGE;
import static com.eastfair.core.base.R.SUCCESS_CODE;

@SpringBootApplication
//@SpringBootApplication(exclude = DruidDataSourceAutoConfigure.class)
@Configuration
@ComponentScan({
        UTIL_PACKAGE
})
@Slf4j
@EnableAspectJAutoProxy(proxyTargetClass = true, exposeProxy = true)
@MapperScan(basePackages = {"com.eastfair.projectcore.dao"})
@EnableDiscoveryClient
@EnableLoginArgResolver
@EnableFeignClients({UTIL_PACKAGE})
//@EnableHystrix
public class ProjectCoreApplication {
    @Autowired
    private AutoloadCacheProperties config;
    @Autowired
    private CacheOps cacheOps;

    @Value("${com.eastfair.systemScene}")
    private static String projectSystemScene;

    @Autowired
    DataIsolationController dataIsolationController;

    private static final Random RANDOM = new Random();

    public static void main(String[] args) throws UnknownHostException {
        SpringApplication application = new SpringApplication(ProjectCoreApplication.class);
        application.addInitializers(new LampMdcAdapterInitializer());
        ConfigurableApplicationContext applicationContext = application.run(args);
        Environment env = applicationContext.getEnvironment();
        log.info("\n----------------------------------------------------------\n\t" +
                        "应用 '{}' 运行成功! 访问连接:\n\t" +
                        "Swagger文档: \t\thttp://{}:{}/doc.html\n\t" +
                        "数据库监控: \t\thttp://{}:{}/druid\n" +
                        "----------------------------------------------------------",
                env.getProperty("spring.application.name"),
                InetAddress.getLocalHost().getHostAddress(),
                env.getProperty("server.port"),
                "127.0.0.1",
                env.getProperty("server.port"));
        //加载雪花id
        executeWorkNode();
        initBusiness();
    }



    /**
     * 加载雪花id
     */
    public static void executeWorkNode() {
        WorkerNode workerNodeEntity = buildWorkerNode();
        SpringUtil.getBean(WorkerNodeService.class).save(workerNodeEntity);
        log.info("Add worker node:{}", JSONObject.toJSONString(workerNodeEntity));
        StaticContextUtil.setStaticProjectWorkId(String.valueOf(workerNodeEntity.getId()));

        WorkerNodeOfUid workerNodeOfUid = new WorkerNodeOfUid();
        BeanUtils.copyProperties(workerNodeEntity,workerNodeOfUid);
        workerNodeOfUid.setId(workerNodeEntity.getId());
        SpringUtil.getBean(CachedUidGenerator.class).initBean(workerNodeOfUid);
    }

    /**
     * Build worker node entity by IP and PORT
     */
    private static WorkerNode buildWorkerNode() {
        WorkerNode workerNodeEntity = new WorkerNode();
        if (DockerUtils.isDocker()) {
            workerNodeEntity.setType(WorkerNodeType.CONTAINER.value());
            workerNodeEntity.setHostName(DockerUtils.getDockerHost());
            workerNodeEntity.setPort(DockerUtils.getDockerPort());

        } else {
            workerNodeEntity.setType(WorkerNodeType.ACTUAL.value());
            workerNodeEntity.setHostName(com.eastfair.uid.baidu.util.NetUtils.getLocalInetAddress().getHostAddress());
            workerNodeEntity.setPort(System.currentTimeMillis() + "-" + RANDOM.nextInt(100000));
        }
        workerNodeEntity.setLaunchDate(LocalDate.now());
        workerNodeEntity.setModified(LocalDateTime.now());
        workerNodeEntity.setCreated(LocalDateTime.now());
        return workerNodeEntity;
    }



    public static void initBusiness() {
        SpringUtil.getBean(DictionaryController.class).initDictData();
//        SpringUtil.getBean(WorkerNodeController.class).createWorkNode();
//
        //加载租户规则信息
//        R<List<TenantRuleVO>> listR = SpringUtil.getBean(TenantRuleController.class).queryTenantTable();
//        if(SUCCESS_CODE == listR.getCode()){
//            List<TenantRuleVO> tenantRuleVOList = listR.getData();
//            if(tenantRuleVOList !=null && !tenantRuleVOList.isEmpty()){
//                StaticContextUtil.setTenantRule(JSONObject.toJSONString(tenantRuleVOList));
//            }
//        }
        //系统数据
        R<List<DataIsolationVo>> listR = SpringUtil.getBean(DataIsolationController.class).queryList(new DataIsolationDTO());
        if (listR.getIsSuccess()) {
            List<DataIsolationVo> dataIsolationVoList = listR.getData();
            StaticContextUtil.setDataIsolcationList(dataIsolationVoList == null ? null : JSON.toJSONString(dataIsolationVoList));
            //设置本系统数据隔离级别
            List<Map> list = new ArrayList<>();
            for (DataIsolationVo dataIsolationVo : dataIsolationVoList) {
                if (dataIsolationVo.getSystemScene().equals(projectSystemScene) && StringUtils.isNotBlank(dataIsolationVo.getDataScope())) {
                    Map map = new HashMap();
                    map.put("projectId", dataIsolationVo.getProjectId());
                    map.put("dataScope", dataIsolationVo.getDataScope());
                    map.put("systemId", dataIsolationVo.getId());
                    map.put("businDataScope", dataIsolationVo.getBusinDataScope());
                    map.put("systemType", dataIsolationVo.getSystemType());
                    list.add(map);
                }
            }
            //本项目系统 是否是基础服务
            if (!CollectionUtils.isEmpty(list)) {
                String systemType = (String) list.get(0).get("systemType");
                String businDataScope = (String) list.get(0).get("businDataScope");
                DataIsolationModel.setSelfDataScope(DataScopeEnum.get(businDataScope));
                DataIsolationModel.setSelfTag(SystemTagEnum.get(systemType));
            }
            StaticContextUtil.setStaticProjectSystemDataScope(list.size() == 0 ? "" : JSON.toJSONString(list));
        }

    }
}
